import { observe } from "./observer/index.js";
import Watcher from "./observer/watcher";
import Dep from "./observer/dep";
export function initState ( vm ) {
  // 先props 在methods 在data 在 computed 在watch  (检测重名 规则是vue自己定的)
  let options = vm.$options;

  if ( options.data ) {
    // 初始化data选项
    initData( vm );
  }

  if ( options.watch ) {
    // 初始化watch
    initWatch( vm );
  }

  if ( options.computed ) {
    // 初始化computed
    initComputed( vm );
  }
}


// 代理实例上的data对象，vm.xx = > vm._data.xx
function proxy ( target, key, property ) {
  Object.defineProperty( target, property, {
    get () {
      return target[ key ][ property ];
    },
    set ( n ) {
      target[ key ][ property ] = n;
    },
  } );
}


function initData ( vm ) {
  // 可能是一个函数data
  let data = vm.$options.data;
  data = vm._data = typeof data === "function" ? data.call( vm ) : data;

  // 代理vm._data上的数据，方便使用 vm.name => vm._data.name
  for ( const key in data ) {
    proxy( vm, "_data", key );
  }
  // 把data数据变成响应式
  observe( data );
}


function initWatch ( vm ) {
  let watch = vm.$options.watch;
  for ( const key in watch ) {
    vm.$watch( key, watch[ key ] );
  }

}

function initComputed ( vm ) {
  let computed = vm.$options.computed;
  vm._computedWatchers = {}
  for ( const key in computed ) {
    vm._computedWatchers[ key ] = new Watcher( vm, computed[ key ], () => { }, {
      lazy: true
    } )

    Object.defineProperty( vm, key, {
      get () {
        let watcher = vm._computedWatchers[ key ]
        // 如果没有缓存
        if ( watcher && watcher.dirty ) {
          // 实际上是调用了计算属性watcher，如果此时有响应式数据取值会触发get操作，让对应的dep订阅器收集计算属性watcher
          watcher.evaluate()
          // 调用结束后计算属性watcher出栈
        }
        // 此时响应式数据只收集了计算属性watcher，如果数据发生变化我们是希望页面视图能够刷新

        if ( Dep.target ) {
          // 因此我们也需要响应式数据收集渲染的watcher
          watcher.depend()
        }
        return watcher.value
      },

    } )
  }
}



